home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcl / src-16f.lha / compiler / mips / call.lisp < prev    next >
Encoding:
Text File  |  1992-05-19  |  40.5 KB  |  1,241 lines

  1. ;;; -*- Package: MIPS; Log: C.Log -*-
  2. ;;;
  3. ;;; **********************************************************************
  4. ;;; This code was written as part of the CMU Common Lisp project at
  5. ;;; Carnegie Mellon University, and has been placed in the public domain.
  6. ;;; If you want to use this code or any part of CMU Common Lisp, please contact
  7. ;;; Scott Fahlman or slisp-group@cs.cmu.edu.
  8. ;;;
  9. (ext:file-comment
  10.   "$Header: call.lisp,v 1.41.2.1 92/05/18 18:26:01 ram Exp $")
  11. ;;;
  12. ;;; **********************************************************************
  13. ;;;
  14. ;;; $Header: call.lisp,v 1.41.2.1 92/05/18 18:26:01 ram Exp $
  15. ;;;
  16. ;;;    This file contains the VM definition of function call for the MIPS.
  17. ;;;
  18. ;;; Written by Rob MacLachlan
  19. ;;;
  20. ;;; Converted for the MIPS by William Lott.
  21. ;;;
  22. (in-package "MIPS")
  23.  
  24.  
  25. ;;;; Interfaces to IR2 conversion:
  26.  
  27. ;;; Standard-Argument-Location  --  Interface
  28. ;;;
  29. ;;;    Return a wired TN describing the N'th full call argument passing
  30. ;;; location.
  31. ;;;
  32. (def-vm-support-routine standard-argument-location (n)
  33.   (declare (type unsigned-byte n))
  34.   (if (< n register-arg-count)
  35.       (make-wired-tn *any-primitive-type*
  36.              register-arg-scn
  37.              (elt register-arg-offsets n))
  38.       (make-wired-tn *any-primitive-type*
  39.              control-stack-arg-scn n)))
  40.  
  41.  
  42. ;;; Make-Return-PC-Passing-Location  --  Interface
  43. ;;;
  44. ;;;    Make a passing location TN for a local call return PC.  If standard is
  45. ;;; true, then use the standard (full call) location, otherwise use any legal
  46. ;;; location.  Even in the non-standard case, this may be restricted by a
  47. ;;; desire to use a subroutine call instruction.
  48. ;;;
  49. (def-vm-support-routine make-return-pc-passing-location (standard)
  50.   (if standard
  51.       (make-wired-tn *any-primitive-type* register-arg-scn lra-offset)
  52.       (make-restricted-tn *any-primitive-type* register-arg-scn)))
  53.  
  54. ;;; Make-Old-FP-Passing-Location  --  Interface
  55. ;;;
  56. ;;;    Similar to Make-Return-PC-Passing-Location, but makes a location to pass
  57. ;;; Old-FP in.  This is (obviously) wired in the standard convention, but is
  58. ;;; totally unrestricted in non-standard conventions, since we can always fetch
  59. ;;; it off of the stack using the arg pointer.
  60. ;;;
  61. (def-vm-support-routine make-old-fp-passing-location (standard)
  62.   (if standard
  63.       (make-wired-tn *fixnum-primitive-type* immediate-arg-scn old-fp-offset)
  64.       (make-normal-tn *fixnum-primitive-type*)))
  65.  
  66. ;;; Make-Old-FP-Save-Location, Make-Return-PC-Save-Location  --  Interface
  67. ;;;
  68. ;;;    Make the TNs used to hold Old-FP and Return-PC within the current
  69. ;;; function.  We treat these specially so that the debugger can find them at a
  70. ;;; known location.
  71. ;;;
  72. (def-vm-support-routine make-old-fp-save-location (env)
  73.   (specify-save-tn
  74.    (environment-debug-live-tn (make-normal-tn *fixnum-primitive-type*) env)
  75.    (make-wired-tn *fixnum-primitive-type*
  76.           control-stack-arg-scn
  77.           old-fp-save-offset)))
  78. ;;;
  79. (def-vm-support-routine make-return-pc-save-location (env)
  80.   (specify-save-tn
  81.    (environment-debug-live-tn (make-normal-tn *any-primitive-type*) env)
  82.    (make-wired-tn *any-primitive-type*
  83.           control-stack-arg-scn
  84.           lra-save-offset)))
  85.  
  86. ;;; Make-Argument-Count-Location  --  Interface
  87. ;;;
  88. ;;;    Make a TN for the standard argument count passing location.  We only
  89. ;;; need to make the standard location, since a count is never passed when we
  90. ;;; are using non-standard conventions.
  91. ;;;
  92. (def-vm-support-routine make-argument-count-location ()
  93.   (make-wired-tn *fixnum-primitive-type* immediate-arg-scn nargs-offset))
  94.  
  95.  
  96. ;;; MAKE-NFP-TN  --  Interface
  97. ;;;
  98. ;;;    Make a TN to hold the number-stack frame pointer.  This is allocated
  99. ;;; once per component, and is component-live.
  100. ;;;
  101. (def-vm-support-routine make-nfp-tn ()
  102.   (component-live-tn
  103.    (make-wired-tn *fixnum-primitive-type* immediate-arg-scn nfp-offset)))
  104.  
  105. ;;; MAKE-STACK-POINTER-TN ()
  106. ;;; 
  107. (def-vm-support-routine make-stack-pointer-tn ()
  108.   (make-normal-tn *fixnum-primitive-type*))
  109.  
  110. ;;; MAKE-NUMBER-STACK-POINTER-TN ()
  111. ;;; 
  112. (def-vm-support-routine make-number-stack-pointer-tn ()
  113.   (make-normal-tn *fixnum-primitive-type*))
  114.  
  115. ;;; Make-Unknown-Values-Locations  --  Interface
  116. ;;;
  117. ;;;    Return a list of TNs that can be used to represent an unknown-values
  118. ;;; continuation within a function.
  119. ;;;
  120. (def-vm-support-routine make-unknown-values-locations ()
  121.   (list (make-stack-pointer-tn)
  122.     (make-normal-tn *fixnum-primitive-type*)))
  123.  
  124.  
  125. ;;; Select-Component-Format  --  Interface
  126. ;;;
  127. ;;;    This function is called by the Entry-Analyze phase, allowing
  128. ;;; VM-dependent initialization of the IR2-Component structure.  We push
  129. ;;; placeholder entries in the Constants to leave room for additional
  130. ;;; noise in the code object header.
  131. ;;;
  132. (def-vm-support-routine select-component-format (component)
  133.   (declare (type component component))
  134.   (dotimes (i code-constants-offset)
  135.     (vector-push-extend nil
  136.             (ir2-component-constants (component-info component))))
  137.   (undefined-value))
  138.  
  139.  
  140. ;;;; Frame hackery:
  141.  
  142. ;;; BYTES-NEEDED-FOR-NON-DESCRIPTOR-STACK-FRAME -- internal
  143. ;;;
  144. ;;; Return the number of bytes needed for the current non-descriptor stack
  145. ;;; frame.  Non-descriptor stack frames must be multiples of 8 bytes on
  146. ;;; the PMAX.
  147. ;;; 
  148. (defun bytes-needed-for-non-descriptor-stack-frame ()
  149.   (* (logandc2 (1+ (sb-allocated-size 'non-descriptor-stack)) 1)
  150.      vm:word-bytes))
  151.  
  152. ;;; Used for setting up the Old-FP in local call.
  153. ;;;
  154. (define-vop (current-fp)
  155.   (:results (val :scs (any-reg)))
  156.   (:generator 1
  157.     (move val fp-tn)))
  158.  
  159. ;;; Used for computing the caller's NFP for use in known-values return.  Only
  160. ;;; works assuming there is no variable size stuff on the nstack.
  161. ;;;
  162. (define-vop (compute-old-nfp)
  163.   (:results (val :scs (any-reg)))
  164.   (:vop-var vop)
  165.   (:generator 1
  166.     (let ((nfp (current-nfp-tn vop)))
  167.       (when nfp
  168.     (inst addu val nfp (bytes-needed-for-non-descriptor-stack-frame))))))
  169.  
  170.  
  171. (define-vop (xep-allocate-frame)
  172.   (:info start-lab)
  173.   (:vop-var vop)
  174.   (:temporary (:scs (non-descriptor-reg)) temp)
  175.   (:generator 1
  176.     ;; Make sure the function is aligned, and drop a label pointing to this
  177.     ;; function header.
  178.     (align vm:lowtag-bits)
  179.     (trace-table-entry trace-table-function-prologue)
  180.     (emit-label start-lab)
  181.     ;; Allocate function header.
  182.     (inst function-header-word)
  183.     (dotimes (i (1- vm:function-header-code-offset))
  184.       (inst word 0))
  185.     ;; The start of the actual code.
  186.     ;; Fix CODE, cause the function object was passed in.
  187.     (let ((entry-point (gen-label)))
  188.       (emit-label entry-point)
  189.       (inst compute-code-from-fn code-tn lip-tn entry-point temp))
  190.     ;; Build our stack frames.
  191.     (inst addu csp-tn fp-tn
  192.       (* vm:word-bytes (sb-allocated-size 'control-stack)))
  193.     (let ((nfp (current-nfp-tn vop)))
  194.       (when nfp
  195.     (inst addu nsp-tn nsp-tn
  196.           (- (bytes-needed-for-non-descriptor-stack-frame)))
  197.     (move nfp nsp-tn)))
  198.     (trace-table-entry trace-table-normal)))
  199.  
  200. (define-vop (allocate-frame)
  201.   (:results (res :scs (any-reg))
  202.         (nfp :scs (any-reg)))
  203.   (:info callee)
  204.   (:generator 2
  205.     (trace-table-entry trace-table-function-prologue)
  206.     (move res csp-tn)
  207.     (inst addu csp-tn csp-tn
  208.       (* vm:word-bytes (sb-allocated-size 'control-stack)))
  209.     (when (ir2-environment-number-stack-p callee)
  210.       (inst addu nsp-tn nsp-tn
  211.         (- (bytes-needed-for-non-descriptor-stack-frame)))
  212.       (move nfp nsp-tn))
  213.     (trace-table-entry trace-table-normal)))
  214.  
  215. ;;; Allocate a partial frame for passing stack arguments in a full call.  Nargs
  216. ;;; is the number of arguments passed.  If no stack arguments are passed, then
  217. ;;; we don't have to do anything.
  218. ;;;
  219. (define-vop (allocate-full-call-frame)
  220.   (:info nargs)
  221.   (:results (res :scs (any-reg)))
  222.   (:generator 2
  223.     (when (> nargs register-arg-count)
  224.       (move res csp-tn)
  225.       (inst addu csp-tn csp-tn (* nargs vm:word-bytes)))))
  226.  
  227.  
  228.  
  229.  
  230. ;;; Default-Unknown-Values  --  Internal
  231. ;;;
  232. ;;;    Emit code needed at the return-point from an unknown-values call for a
  233. ;;; fixed number of values.  Values is the head of the TN-Ref list for the
  234. ;;; locations that the values are to be received into.  Nvals is the number of
  235. ;;; values that are to be received (should equal the length of Values).
  236. ;;;
  237. ;;;    Move-Temp is a Descriptor-Reg TN used as a temporary.
  238. ;;;
  239. ;;;    This code exploits the fact that in the unknown-values convention, a
  240. ;;; single value return returns at the return PC + 8, whereas a return of other
  241. ;;; than one value returns directly at the return PC.
  242. ;;;
  243. ;;;    If 0 or 1 values are expected, then we just emit an instruction to reset
  244. ;;; the SP (which will only be executed when other than 1 value is returned.)
  245. ;;;
  246. ;;; In the general case, we have to do three things:
  247. ;;;  -- Default unsupplied register values.  This need only be done when a
  248. ;;;     single value is returned, since register values are defaulted by the
  249. ;;;     called in the non-single case.
  250. ;;;  -- Default unsupplied stack values.  This needs to be done whenever there
  251. ;;;     are stack values.
  252. ;;;  -- Reset SP.  This must be done whenever other than 1 value is returned,
  253. ;;;     regardless of the number of values desired.
  254. ;;;
  255. ;;; The general-case code looks like this:
  256. #|
  257.     b regs-defaulted        ; Skip if MVs
  258.     nop
  259.  
  260.     move a1 null-tn            ; Default register values
  261.     ...
  262.     loadi nargs 1            ; Force defaulting of stack values
  263.     move old-fp csp            ; Set up args for SP resetting
  264.  
  265. regs-defaulted
  266.     subu temp nargs register-arg-count
  267.  
  268.     bltz temp default-value-7    ; jump to default code
  269.         addu temp temp -1
  270.     loadw move-temp old-fp-tn 6    ; Move value to correct location.
  271.     store-stack-tn val4-tn move-temp
  272.  
  273.     bltz temp default-value-8
  274.         addu temp temp -1
  275.     loadw move-temp old-fp-tn 7
  276.     store-stack-tn val5-tn move-temp
  277.  
  278.     ...
  279.  
  280. defaulting-done
  281.     move sp old-fp            ; Reset SP.
  282. <end of code>
  283.  
  284. <elsewhere>
  285. default-value-7
  286.     store-stack-tn val4-tn null-tn    ; Nil out 7'th value. (first on stack)
  287.  
  288. default-value-8
  289.     store-stack-tn val5-tn null-tn    ; Nil out 8'th value.
  290.  
  291.     ...
  292.  
  293.     br defaulting-done
  294.         nop
  295. |#
  296. ;;;
  297. (defun default-unknown-values (values nvals move-temp temp lra-label)
  298.   (declare (type (or tn-ref null) values)
  299.        (type unsigned-byte nvals) (type tn move-temp temp))
  300.   (if (<= nvals 1)
  301.       (progn
  302.     (move csp-tn old-fp-tn)
  303.     (inst nop)
  304.     (inst entry-point)
  305.     (inst compute-code-from-lra code-tn code-tn lra-label temp))
  306.       (let ((regs-defaulted (gen-label))
  307.         (defaulting-done (gen-label))
  308.         (default-stack-vals (gen-label)))
  309.     ;; Branch off to the MV case.
  310.     (inst b regs-defaulted)
  311.     ;; If there are no stack results, clear the stack now.
  312.     (if (> nvals register-arg-count)
  313.         (inst addu temp nargs-tn (fixnum (- register-arg-count)))
  314.         (move csp-tn old-fp-tn))
  315.     (inst entry-point)
  316.     
  317.     ;; Do the single value calse.
  318.     (do ((i 1 (1+ i))
  319.          (val (tn-ref-across values) (tn-ref-across val)))
  320.         ((= i (min nvals register-arg-count)))
  321.       (move (tn-ref-tn val) null-tn))
  322.     (when (> nvals register-arg-count)
  323.       (inst b default-stack-vals)
  324.       (move old-fp-tn csp-tn))
  325.     
  326.     (emit-label regs-defaulted)
  327.     
  328.     (when (> nvals register-arg-count)
  329.       ;; If there are stack results, we have to default them
  330.       ;; and clear the stack.
  331.       (collect ((defaults))
  332.         (do ((i register-arg-count (1+ i))
  333.          (val (do ((i 0 (1+ i))
  334.                (val values (tn-ref-across val)))
  335.               ((= i register-arg-count) val))
  336.               (tn-ref-across val)))
  337.         ((null val))
  338.           
  339.           (let ((default-lab (gen-label))
  340.             (tn (tn-ref-tn val)))
  341.         (defaults (cons default-lab tn))
  342.         
  343.         (inst bltz temp default-lab)
  344.         (inst lw move-temp old-fp-tn (* i vm:word-bytes))
  345.         (inst addu temp temp (fixnum -1))
  346.         (store-stack-tn tn move-temp)))
  347.         
  348.         (emit-label defaulting-done)
  349.         (move csp-tn old-fp-tn)
  350.         
  351.         (let ((defaults (defaults)))
  352.           (assert defaults)
  353.           (assemble (*elsewhere*)
  354.         (trace-table-entry trace-table-call-site)
  355.         (emit-label default-stack-vals)
  356.         (do ((remaining defaults (cdr remaining)))
  357.             ((null remaining))
  358.           (let ((def (car remaining)))
  359.             (emit-label (car def))
  360.             (when (null (cdr remaining))
  361.               (inst b defaulting-done))
  362.             (store-stack-tn (cdr def) null-tn)))
  363.         (trace-table-entry trace-table-normal)))))
  364.  
  365.     (inst compute-code-from-lra code-tn code-tn lra-label temp)))
  366.   (undefined-value))
  367.  
  368.  
  369. ;;;; Unknown values receiving:
  370.  
  371. ;;; Receive-Unknown-Values  --  Internal
  372. ;;;
  373. ;;;    Emit code needed at the return point for an unknown-values call for an
  374. ;;; arbitrary number of values.
  375. ;;;
  376. ;;;    We do the single and non-single cases with no shared code: there doesn't
  377. ;;; seem to be any potential overlap, and receiving a single value is more
  378. ;;; important efficiency-wise.
  379. ;;;
  380. ;;;    When there is a single value, we just push it on the stack, returning
  381. ;;; the old SP and 1.
  382. ;;;
  383. ;;;    When there is a variable number of values, we move all of the argument
  384. ;;; registers onto the stack, and return Args and Nargs.
  385. ;;;
  386. ;;;    Args and Nargs are TNs wired to the named locations.  We must
  387. ;;; explicitly allocate these TNs, since their lifetimes overlap with the
  388. ;;; results Start and Count (also, it's nice to be able to target them).
  389. ;;;
  390. (defun receive-unknown-values (args nargs start count lra-label temp)
  391.   (declare (type tn args nargs start count temp))
  392.   (let ((variable-values (gen-label))
  393.     (done (gen-label)))
  394.     (inst b variable-values)
  395.     (inst nop)
  396.     (inst entry-point)
  397.     
  398.     (inst compute-code-from-lra code-tn code-tn lra-label temp)
  399.     (inst addu csp-tn csp-tn 4)
  400.     (storew (first register-arg-tns) csp-tn -1)
  401.     (inst addu start csp-tn -4)
  402.     (inst li count (fixnum 1))
  403.     
  404.     (emit-label done)
  405.     
  406.     (assemble (*elsewhere*)
  407.       (trace-table-entry trace-table-call-site)
  408.       (emit-label variable-values)
  409.       (inst compute-code-from-lra code-tn code-tn lra-label temp)
  410.       (do ((arg register-arg-tns (rest arg))
  411.        (i 0 (1+ i)))
  412.       ((null arg))
  413.     (storew (first arg) args i))
  414.       (move start args)
  415.       (move count nargs)
  416.       (inst b done)
  417.       (inst nop)
  418.       (trace-table-entry trace-table-normal)))
  419.   (undefined-value))
  420.  
  421.  
  422. ;;; VOP that can be inherited by unknown values receivers.  The main thing this
  423. ;;; handles is allocation of the result temporaries.
  424. ;;;
  425. (define-vop (unknown-values-receiver)
  426.   (:results
  427.    (start :scs (any-reg))
  428.    (count :scs (any-reg)))
  429.   (:temporary (:sc descriptor-reg :offset old-fp-offset
  430.            :from :eval :to (:result 0))
  431.           values-start)
  432.   (:temporary (:sc any-reg :offset nargs-offset
  433.            :from :eval :to (:result 1))
  434.           nvals)
  435.   (:temporary (:scs (non-descriptor-reg)) temp))
  436.  
  437.  
  438.  
  439. ;;;; Local call with unknown values convention return:
  440.  
  441. ;;; Non-TR local call for a fixed number of values passed according to the
  442. ;;; unknown values convention.
  443. ;;;
  444. ;;; Args are the argument passing locations, which are specified only to
  445. ;;; terminate their lifetimes in the caller.
  446. ;;;
  447. ;;; Values are the return value locations (wired to the standard passing
  448. ;;; locations).
  449. ;;;
  450. ;;; Save is the save info, which we can ignore since saving has been done.
  451. ;;; Return-PC is the TN that the return PC should be passed in.
  452. ;;; Target is a continuation pointing to the start of the called function.
  453. ;;; Nvals is the number of values received.
  454. ;;;
  455. ;;; Note: we can't use normal load-tn allocation for the fixed args, since all
  456. ;;; registers may be tied up by the more operand.  Instead, we use
  457. ;;; MAYBE-LOAD-STACK-TN.
  458. ;;;
  459. (define-vop (call-local)
  460.   (:args (fp)
  461.      (nfp)
  462.      (args :more t))
  463.   (:results (values :more t))
  464.   (:save-p t)
  465.   (:move-args :local-call)
  466.   (:info arg-locs callee target nvals)
  467.   (:vop-var vop)
  468.   (:temporary (:scs (descriptor-reg) :from :eval) move-temp)
  469.   (:temporary (:scs (non-descriptor-reg)) temp)
  470.   (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save)
  471.   (:temporary (:sc any-reg :offset old-fp-offset :from :eval) ocfp)
  472.   (:ignore arg-locs args ocfp)
  473.   (:generator 5
  474.     (trace-table-entry trace-table-call-site)
  475.     (let ((label (gen-label))
  476.       (cur-nfp (current-nfp-tn vop)))
  477.       (when cur-nfp
  478.     (store-stack-tn nfp-save cur-nfp))
  479.       (let ((callee-nfp (callee-nfp-tn callee)))
  480.     (when callee-nfp
  481.       (move callee-nfp nfp)))
  482.       (maybe-load-stack-tn fp-tn fp)
  483.       (inst compute-lra-from-code
  484.         (callee-return-pc-tn callee) code-tn label temp)
  485.       (inst b target)
  486.       (inst nop)
  487.       (emit-return-pc label)
  488.       (note-this-location vop :unknown-return)
  489.       (default-unknown-values values nvals move-temp temp label)
  490.       (when cur-nfp
  491.     (load-stack-tn cur-nfp nfp-save)))
  492.     (trace-table-entry trace-table-normal)))
  493.  
  494.  
  495. ;;; Non-TR local call for a variable number of return values passed according
  496. ;;; to the unknown values convention.  The results are the start of the values
  497. ;;; glob and the number of values received.
  498. ;;;
  499. ;;; Note: we can't use normal load-tn allocation for the fixed args, since all
  500. ;;; registers may be tied up by the more operand.  Instead, we use
  501. ;;; MAYBE-LOAD-STACK-TN.
  502. ;;;
  503. (define-vop (multiple-call-local unknown-values-receiver)
  504.   (:args (fp)
  505.      (nfp)
  506.      (args :more t))
  507.   (:save-p t)
  508.   (:move-args :local-call)
  509.   (:info save callee target)
  510.   (:ignore args save)
  511.   (:vop-var vop)
  512.   (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save)
  513.   (:generator 20
  514.     (trace-table-entry trace-table-call-site)
  515.     (let ((label (gen-label))
  516.       (cur-nfp (current-nfp-tn vop)))
  517.       (when cur-nfp
  518.     (store-stack-tn nfp-save cur-nfp))
  519.       (let ((callee-nfp (callee-nfp-tn callee)))
  520.     (when callee-nfp
  521.       (move callee-nfp nfp)))
  522.       (maybe-load-stack-tn fp-tn fp)
  523.       (inst compute-lra-from-code
  524.         (callee-return-pc-tn callee) code-tn label temp)
  525.       (inst b target)
  526.       (inst nop)
  527.       (emit-return-pc label)
  528.       (note-this-location vop :unknown-return)
  529.       (receive-unknown-values values-start nvals start count label temp)
  530.       (when cur-nfp
  531.     (load-stack-tn cur-nfp nfp-save)))
  532.     (trace-table-entry trace-table-normal)))
  533.  
  534.  
  535. ;;;; Local call with known values return:
  536.  
  537. ;;; Non-TR local call with known return locations.  Known-value return works
  538. ;;; just like argument passing in local call.
  539. ;;;
  540. ;;; Note: we can't use normal load-tn allocation for the fixed args, since all
  541. ;;; registers may be tied up by the more operand.  Instead, we use
  542. ;;; MAYBE-LOAD-STACK-TN.
  543. ;;;
  544. (define-vop (known-call-local)
  545.   (:args (fp)
  546.      (nfp)
  547.      (args :more t))
  548.   (:results (res :more t))
  549.   (:move-args :local-call)
  550.   (:save-p t)
  551.   (:info save callee target)
  552.   (:ignore args res save)
  553.   (:vop-var vop)
  554.   (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save)
  555.   (:temporary (:scs (non-descriptor-reg)) temp)
  556.   (:generator 5
  557.     (trace-table-entry trace-table-call-site)
  558.     (let ((label (gen-label))
  559.       (cur-nfp (current-nfp-tn vop)))
  560.       (when cur-nfp
  561.     (store-stack-tn nfp-save cur-nfp))
  562.       (let ((callee-nfp (callee-nfp-tn callee)))
  563.     (when callee-nfp
  564.       (move callee-nfp nfp)))
  565.       (maybe-load-stack-tn fp-tn fp)
  566.       (inst compute-lra-from-code
  567.         (callee-return-pc-tn callee) code-tn label temp)
  568.       (inst b target)
  569.       (inst nop)
  570.       (emit-return-pc label)
  571.       (note-this-location vop :known-return)
  572.       (when cur-nfp
  573.     (load-stack-tn cur-nfp nfp-save)))
  574.     (trace-table-entry trace-table-normal)))
  575.  
  576. ;;; Return from known values call.  We receive the return locations as
  577. ;;; arguments to terminate their lifetimes in the returning function.  We
  578. ;;; restore FP and CSP and jump to the Return-PC.
  579. ;;;
  580. ;;; Note: we can't use normal load-tn allocation for the fixed args, since all
  581. ;;; registers may be tied up by the more operand.  Instead, we use
  582. ;;; MAYBE-LOAD-STACK-TN.
  583. ;;;
  584. (define-vop (known-return)
  585.   (:args (old-fp :target old-fp-temp)
  586.      (return-pc :target return-pc-temp)
  587.      (vals :more t))
  588.   (:temporary (:sc any-reg :from (:argument 0)) old-fp-temp)
  589.   (:temporary (:sc descriptor-reg :from (:argument 1)) return-pc-temp)
  590.   (:temporary (:scs (interior-reg) :type interior) lip)
  591.   (:move-args :known-return)
  592.   (:info val-locs)
  593.   (:ignore val-locs vals)
  594.   (:vop-var vop)
  595.   (:generator 6
  596.     (trace-table-entry trace-table-function-epilogue)
  597.     (maybe-load-stack-tn old-fp-temp old-fp)
  598.     (maybe-load-stack-tn return-pc-temp return-pc)
  599.     (move csp-tn fp-tn)
  600.     (let ((cur-nfp (current-nfp-tn vop)))
  601.       (when cur-nfp
  602.     (inst addu nsp-tn cur-nfp
  603.           (bytes-needed-for-non-descriptor-stack-frame))))
  604.     (inst addu lip return-pc-temp (- vm:word-bytes vm:other-pointer-type))
  605.     (inst j lip)
  606.     (move fp-tn old-fp-temp)
  607.     (trace-table-entry trace-table-normal)))
  608.  
  609.  
  610. ;;;; Full call:
  611. ;;;
  612. ;;;    There is something of a cross-product effect with full calls.  Different
  613. ;;; versions are used depending on whether we know the number of arguments or
  614. ;;; the name of the called function, and whether we want fixed values, unknown
  615. ;;; values, or a tail call.
  616. ;;;
  617. ;;; In full call, the arguments are passed creating a partial frame on the
  618. ;;; stack top and storing stack arguments into that frame.  On entry to the
  619. ;;; callee, this partial frame is pointed to by FP.  If there are no stack
  620. ;;; arguments, we don't bother allocating a partial frame, and instead set FP
  621. ;;; to SP just before the call.
  622.  
  623. ;;; Define-Full-Call  --  Internal
  624. ;;;
  625. ;;;    This macro helps in the definition of full call VOPs by avoiding code
  626. ;;; replication in defining the cross-product VOPs.
  627. ;;;
  628. ;;; Name is the name of the VOP to define.
  629. ;;; 
  630. ;;; Named is true if the first argument is a symbol whose global function
  631. ;;; definition is to be called.
  632. ;;;
  633. ;;; Return is either :Fixed, :Unknown or :Tail:
  634. ;;; -- If :Fixed, then the call is for a fixed number of values, returned in
  635. ;;;    the standard passing locations (passed as result operands).
  636. ;;; -- If :Unknown, then the result values are pushed on the stack, and the
  637. ;;;    result values are specified by the Start and Count as in the
  638. ;;;    unknown-values continuation representation.
  639. ;;; -- If :Tail, then do a tail-recursive call.  No values are returned.
  640. ;;;    The Old-Fp and Return-PC are passed as the second and third arguments.
  641. ;;;
  642. ;;; In non-tail calls, the pointer to the stack arguments is passed as the last
  643. ;;; fixed argument.  If Variable is false, then the passing locations are
  644. ;;; passed as a more arg.  Variable is true if there are a variable number of
  645. ;;; arguments passed on the stack.  Variable cannot be specified with :Tail
  646. ;;; return.  TR variable argument call is implemented separately.
  647. ;;;
  648. ;;; In tail call with fixed arguments, the passing locations are passed as a
  649. ;;; more arg, but there is no new-FP, since the arguments have been set up in
  650. ;;; the current frame.
  651. ;;;
  652. (defmacro define-full-call (name named return variable)
  653.   (assert (not (and variable (eq return :tail))))
  654.   `(define-vop (,name
  655.         ,@(when (eq return :unknown)
  656.             '(unknown-values-receiver)))
  657.      (:args
  658.       ,@(unless (eq return :tail)
  659.       '((new-fp :scs (any-reg) :to :eval)))
  660.  
  661.       ,(if named
  662.        '(name :target name-pass)
  663.        '(arg-fun :target lexenv))
  664.       
  665.       ,@(when (eq return :tail)
  666.       '((old-fp :target old-fp-pass)
  667.         (return-pc :target return-pc-pass)))
  668.       
  669.       ,@(unless variable '((args :more t :scs (descriptor-reg)))))
  670.  
  671.      ,@(when (eq return :fixed)
  672.      '((:results (values :more t))))
  673.    
  674.      ,@(unless (eq return :tail)
  675.      `((:save-p t)
  676.        ,@(unless variable
  677.            '((:move-args :full-call)))))
  678.  
  679.      (:vop-var vop)
  680.      (:info ,@(unless (or variable (eq return :tail)) '(arg-locs))
  681.         ,@(unless variable '(nargs))
  682.         ,@(when (eq return :fixed) '(nvals)))
  683.  
  684.      (:ignore
  685.       ,@(unless (or variable (eq return :tail)) '(arg-locs))
  686.       ,@(unless variable '(args)))
  687.  
  688.      (:temporary (:sc descriptor-reg
  689.           :offset old-fp-offset
  690.           :from (:argument 1)
  691.           ,@(unless (eq return :fixed)
  692.               '(:to :eval)))
  693.          old-fp-pass)
  694.  
  695.      (:temporary (:sc descriptor-reg
  696.           :offset lra-offset
  697.           :from (:argument ,(if (eq return :tail) 2 1))
  698.           :to :eval)
  699.          return-pc-pass)
  700.  
  701.      ,@(if named
  702.      `((:temporary (:sc descriptor-reg :offset cname-offset
  703.             :from (:argument ,(if (eq return :tail) 0 1))
  704.             :to :eval)
  705.                name-pass))
  706.  
  707.      `((:temporary (:sc descriptor-reg :offset lexenv-offset
  708.             :from (:argument ,(if (eq return :tail) 0 1))
  709.             :to :eval)
  710.                lexenv)
  711.        (:temporary (:scs (descriptor-reg) :from (:argument 0) :to :eval)
  712.                function)))
  713.  
  714.      (:temporary (:sc any-reg :offset nargs-offset :to :eval)
  715.          nargs-pass)
  716.  
  717.      ,@(when variable
  718.      (mapcar #'(lambda (name offset)
  719.              `(:temporary (:sc descriptor-reg
  720.                    :offset ,offset
  721.                    :to :eval)
  722.              ,name))
  723.          register-arg-names register-arg-offsets))
  724.      ,@(when (eq return :fixed)
  725.      '((:temporary (:scs (descriptor-reg) :from :eval) move-temp)))
  726.  
  727.      ,@(unless (eq return :tail)
  728.      '((:temporary (:scs (non-descriptor-reg) :from :eval) temp)
  729.        (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save)))
  730.  
  731.      (:temporary (:scs (interior-reg) :type interior) lip)
  732.  
  733.      (:generator ,(+ (if named 5 0)
  734.              (if variable 19 1)
  735.              (if (eq return :tail) 0 10)
  736.              15
  737.              (if (eq return :unknown) 25 0))
  738.        (trace-table-entry trace-table-call-site)
  739.        (let* ((cur-nfp (current-nfp-tn vop))
  740.           ,@(unless (eq return :tail)
  741.           '((lra-label (gen-label))))
  742.           (filler
  743.            (remove nil
  744.                (list :load-nargs
  745.                  ,@(if (eq return :tail)
  746.                    '((unless (location= old-fp old-fp-pass)
  747.                        :load-old-fp)
  748.                      (unless (location= return-pc
  749.                             return-pc-pass)
  750.                        :load-return-pc)
  751.                      (when cur-nfp
  752.                        :frob-nfp))
  753.                    '(:comp-lra
  754.                      (when cur-nfp
  755.                        :frob-nfp)
  756.                      :save-fp
  757.                      :load-fp))))))
  758.      (flet ((do-next-filler ()
  759.           (let* ((next (pop filler))
  760.              (what (if (consp next) (car next) next)))
  761.             (ecase what
  762.               (:load-nargs
  763.                ,@(if variable
  764.                  `((inst subu nargs-pass csp-tn new-fp)
  765.                    ,@(let ((index -1))
  766.                    (mapcar #'(lambda (name)
  767.                            `(inst lw ,name new-fp
  768.                               ,(ash (incf index)
  769.                                 vm:word-shift)))
  770.                        register-arg-names)))
  771.                  '((inst li nargs-pass (fixnum nargs)))))
  772.               ,@(if (eq return :tail)
  773.                 '((:load-old-fp
  774.                    (sc-case old-fp
  775.                  (any-reg
  776.                   (inst move old-fp-pass old-fp))
  777.                  (control-stack
  778.                   (inst lw old-fp-pass fp-tn
  779.                     (ash (tn-offset old-fp)
  780.                          vm:word-shift)))))
  781.                   (:load-return-pc
  782.                    (sc-case return-pc
  783.                  (descriptor-reg
  784.                   (inst move return-pc-pass return-pc))
  785.                  (control-stack
  786.                   (inst lw return-pc-pass fp-tn
  787.                     (ash (tn-offset return-pc)
  788.                          vm:word-shift)))))
  789.                   (:frob-nfp
  790.                    (inst addu nsp-tn cur-nfp
  791.                      (bytes-needed-for-non-descriptor-stack-frame))))
  792.                 `((:comp-lra
  793.                    (inst compute-lra-from-code
  794.                      return-pc-pass code-tn lra-label temp))
  795.                   (:frob-nfp
  796.                    (store-stack-tn nfp-save cur-nfp))
  797.                   (:save-fp
  798.                    (inst move old-fp-pass fp-tn))
  799.                   (:load-fp
  800.                    ,(if variable
  801.                     '(move fp-tn new-fp)
  802.                     '(if (> nargs register-arg-count)
  803.                      (move fp-tn new-fp)
  804.                      (move fp-tn csp-tn))))))
  805.               ((nil)
  806.                (inst nop))))))
  807.  
  808.        ,@(if named
  809.          `((sc-case name
  810.              (descriptor-reg (move name-pass name))
  811.              (control-stack
  812.               (inst lw name-pass fp-tn
  813.                 (ash (tn-offset name) vm:word-shift))
  814.               (do-next-filler))
  815.              (random-immediate
  816.               (load-symbol name-pass (tn-value name)))
  817.              (constant
  818.               (inst lw name-pass code-tn
  819.                 (- (ash (tn-offset name) vm:word-shift)
  820.                    vm:other-pointer-type))
  821.               (do-next-filler)))
  822.            (inst lw lip name-pass
  823.              (- (ash vm:symbol-raw-function-addr-slot
  824.                  vm:word-shift)
  825.                 vm:other-pointer-type))
  826.            (do-next-filler))
  827.          `((sc-case arg-fun
  828.              (descriptor-reg (move lexenv arg-fun))
  829.              (control-stack
  830.               (inst lw lexenv fp-tn
  831.                 (ash (tn-offset arg-fun) vm:word-shift))
  832.               (do-next-filler))
  833.              (constant
  834.               (inst lw lexenv code-tn
  835.                 (- (ash (tn-offset arg-fun) vm:word-shift)
  836.                    vm:other-pointer-type))
  837.               (do-next-filler)))
  838.            (inst lw function lexenv
  839.              (- (ash vm:closure-function-slot vm:word-shift)
  840.                 vm:function-pointer-type))
  841.            (do-next-filler)
  842.            (inst addu lip function
  843.              (- (ash vm:function-header-code-offset
  844.                  vm:word-shift)
  845.                 vm:function-pointer-type))))
  846.        (loop
  847.          (if (cdr filler)
  848.          (do-next-filler)
  849.          (return)))
  850.        
  851.        (inst j lip)
  852.        (do-next-filler))
  853.  
  854.      ,@(ecase return
  855.          (:fixed
  856.           '((emit-return-pc lra-label)
  857.         (note-this-location vop :unknown-return)
  858.         (default-unknown-values values nvals move-temp temp lra-label)
  859.         (when cur-nfp
  860.           (load-stack-tn cur-nfp nfp-save))))
  861.          (:unknown
  862.           '((emit-return-pc lra-label)
  863.         (note-this-location vop :unknown-return)
  864.         (receive-unknown-values values-start nvals start count
  865.                     lra-label temp)
  866.         (when cur-nfp
  867.           (load-stack-tn cur-nfp nfp-save))))
  868.          (:tail)))
  869.        (trace-table-entry trace-table-normal))))
  870.  
  871.  
  872. (define-full-call call nil :fixed nil)
  873. (define-full-call call-named t :fixed nil)
  874. (define-full-call multiple-call nil :unknown nil)
  875. (define-full-call multiple-call-named t :unknown nil)
  876. (define-full-call tail-call nil :tail nil)
  877. (define-full-call tail-call-named t :tail nil)
  878.  
  879. (define-full-call call-variable nil :fixed t)
  880. (define-full-call multiple-call-variable nil :unknown t)
  881.  
  882.  
  883. ;;; Defined separately, since needs special code that BLT's the arguments
  884. ;;; down.
  885. ;;;
  886. (define-vop (tail-call-variable)
  887.   (:args
  888.    (args-arg :scs (any-reg) :target args)
  889.    (function-arg :scs (descriptor-reg) :target lexenv)
  890.    (old-fp-arg :scs (any-reg) :target old-fp)
  891.    (lra-arg :scs (descriptor-reg) :target lra))
  892.  
  893.   (:temporary (:sc any-reg :offset nl0-offset :from (:argument 0)) args)
  894.   (:temporary (:sc any-reg :offset lexenv-offset :from (:argument 1)) lexenv)
  895.   (:temporary (:sc any-reg :offset old-fp-offset :from (:argument 2)) old-fp)
  896.   (:temporary (:sc any-reg :offset lra-offset :from (:argument 3)) lra)
  897.  
  898.   (:vop-var vop)
  899.  
  900.   (:generator 75
  901.  
  902.     ;; Move these into the passing locations if they are not already there.
  903.     (move args args-arg)
  904.     (move lexenv function-arg)
  905.     (move old-fp old-fp-arg)
  906.     (move lra lra-arg)
  907.  
  908.     ;; Clear the number stack if anything is there.
  909.     (let ((cur-nfp (current-nfp-tn vop)))
  910.       (when cur-nfp
  911.     (inst addu nsp-tn cur-nfp
  912.           (bytes-needed-for-non-descriptor-stack-frame))))
  913.  
  914.     ;; And jump to the assembly-routine that does the bliting.
  915.     (inst j (make-fixup 'tail-call-variable :assembly-routine))
  916.     (inst nop)))
  917.  
  918.  
  919. ;;;; Unknown values return:
  920.  
  921.  
  922. ;;; Do unknown-values return of a fixed number of values.  The Values are
  923. ;;; required to be set up in the standard passing locations.  Nvals is the
  924. ;;; number of values returned.
  925. ;;;
  926. ;;; If returning a single value, then deallocate the current frame, restore
  927. ;;; FP and jump to the single-value entry at Return-PC + 8.
  928. ;;;
  929. ;;; If returning other than one value, then load the number of values returned,
  930. ;;; NIL out unsupplied values registers, restore FP and return at Return-PC.
  931. ;;; When there are stack values, we must initialize the argument pointer to
  932. ;;; point to the beginning of the values block (which is the beginning of the
  933. ;;; current frame.)
  934. ;;;
  935. (define-vop (return)
  936.   (:args
  937.    (old-fp :scs (any-reg))
  938.    (return-pc :scs (descriptor-reg) :to (:eval 1))
  939.    (values :more t))
  940.   (:ignore values)
  941.   (:info nvals)
  942.   (:temporary (:sc descriptor-reg :offset a0-offset :from (:eval 0)) a0)
  943.   (:temporary (:sc descriptor-reg :offset a1-offset :from (:eval 0)) a1)
  944.   (:temporary (:sc descriptor-reg :offset a2-offset :from (:eval 0)) a2)
  945.   (:temporary (:sc descriptor-reg :offset a3-offset :from (:eval 0)) a3)
  946.   (:temporary (:sc descriptor-reg :offset a4-offset :from (:eval 0)) a4)
  947.   (:temporary (:sc descriptor-reg :offset a5-offset :from (:eval 0)) a5)
  948.   (:temporary (:sc any-reg :offset nargs-offset) nargs)
  949.   (:temporary (:sc any-reg :offset old-fp-offset) val-ptr)
  950.   (:temporary (:scs (interior-reg) :type interior) lip)
  951.   (:vop-var vop)
  952.   (:generator 6
  953.     ;; Clear the number stack.
  954.     (trace-table-entry trace-table-function-epilogue)
  955.     (let ((cur-nfp (current-nfp-tn vop)))
  956.       (when cur-nfp
  957.     (inst addu nsp-tn cur-nfp
  958.           (bytes-needed-for-non-descriptor-stack-frame))))
  959.     (cond ((= nvals 1)
  960.        ;; Clear the control stack, and restore the frame pointer.
  961.        (move csp-tn fp-tn)
  962.        (move fp-tn old-fp)
  963.        ;; Out of here.
  964.        (lisp-return return-pc lip :offset 2))
  965.       (t
  966.        ;; Establish the values pointer and values count.
  967.        (move val-ptr fp-tn)
  968.        (inst li nargs (fixnum nvals))
  969.        ;; restore the frame pointer and clear as much of the control
  970.        ;; stack as possible.
  971.        (move fp-tn old-fp)
  972.        (inst addu csp-tn val-ptr (* nvals word-bytes))
  973.        ;; pre-default any argument register that need it.
  974.        (when (< nvals register-arg-count)
  975.          (dolist (reg (subseq (list a0 a1 a2 a3 a4 a5) nvals))
  976.            (move reg null-tn)))
  977.        ;; And away we go.
  978.        (lisp-return return-pc lip)))
  979.     (trace-table-entry trace-table-normal)))
  980.  
  981. ;;; Do unknown-values return of an arbitrary number of values (passed on the
  982. ;;; stack.)  We check for the common case of a single return value, and do that
  983. ;;; inline using the normal single value return convention.  Otherwise, we
  984. ;;; branch off to code that calls an assembly-routine.
  985. ;;;
  986. (define-vop (return-multiple)
  987.   (:args
  988.    (old-fp-arg :scs (any-reg) :to (:eval 1))
  989.    (lra-arg :scs (descriptor-reg) :to (:eval 1))
  990.    (vals-arg :scs (any-reg) :target vals)
  991.    (nvals-arg :scs (any-reg) :target nvals))
  992.  
  993.   (:temporary (:sc any-reg :offset nl1-offset :from (:argument 0)) old-fp)
  994.   (:temporary (:sc descriptor-reg :offset lra-offset :from (:argument 1)) lra)
  995.   (:temporary (:sc any-reg :offset nl0-offset :from (:argument 2)) vals)
  996.   (:temporary (:sc any-reg :offset nargs-offset :from (:argument 3)) nvals)
  997.   (:temporary (:sc descriptor-reg :offset a0-offset) a0)
  998.   (:temporary (:scs (interior-reg) :type interior) lip)
  999.  
  1000.   (:vop-var vop)
  1001.  
  1002.   (:generator 13
  1003.     (trace-table-entry trace-table-function-epilogue)
  1004.     (let ((not-single (gen-label)))
  1005.       ;; Clear the number stack.
  1006.       (let ((cur-nfp (current-nfp-tn vop)))
  1007.     (when cur-nfp
  1008.       (inst addu nsp-tn cur-nfp
  1009.         (bytes-needed-for-non-descriptor-stack-frame))))
  1010.  
  1011.       ;; Check for the single case.
  1012.       (inst li a0 (fixnum 1))
  1013.       (inst bne nvals-arg a0 not-single)
  1014.       (inst lw a0 vals-arg)
  1015.  
  1016.       ;; Return with one value.
  1017.       (move csp-tn fp-tn)
  1018.       (move fp-tn old-fp-arg)
  1019.       (lisp-return lra-arg lip :offset 2)
  1020.         
  1021.       ;; Nope, not the single case.
  1022.       (emit-label not-single)
  1023.       (move old-fp old-fp-arg)
  1024.       (move lra lra-arg)
  1025.       (move vals vals-arg)
  1026.       (move nvals nvals-arg)
  1027.       (inst j (make-fixup 'return-multiple :assembly-routine))
  1028.       (inst nop))
  1029.     (trace-table-entry trace-table-normal)))
  1030.  
  1031.  
  1032.  
  1033. ;;;; XEP hackery:
  1034.  
  1035.  
  1036. ;;; We don't need to do anything special for regular functions.
  1037. ;;;
  1038. (define-vop (setup-environment)
  1039.   (:info label)
  1040.   (:ignore label)
  1041.   (:generator 0
  1042.     ;; Don't bother doing anything.
  1043.     ))
  1044.  
  1045. ;;; Get the lexical environment from it's passing location.
  1046. ;;;
  1047. (define-vop (setup-closure-environment)
  1048.   (:temporary (:sc descriptor-reg :offset lexenv-offset :target closure
  1049.            :to (:result 0))
  1050.           lexenv)
  1051.   (:results (closure :scs (descriptor-reg)))
  1052.   (:info label)
  1053.   (:ignore label)
  1054.   (:generator 6
  1055.     ;; Get result.
  1056.     (move closure lexenv)))
  1057.  
  1058. ;;; Copy a more arg from the argument area to the end of the current frame.
  1059. ;;; Fixed is the number of non-more arguments. 
  1060. ;;;
  1061. (define-vop (copy-more-arg)
  1062.   (:temporary (:sc any-reg :offset nl0-offset) result)
  1063.   (:temporary (:sc any-reg :offset nl1-offset) count)
  1064.   (:temporary (:sc any-reg :offset nl2-offset) src)
  1065.   (:temporary (:sc any-reg :offset nl3-offset) dst)
  1066.   (:temporary (:sc descriptor-reg :offset l0-offset) temp)
  1067.   (:info fixed)
  1068.   (:generator 20
  1069.     (let ((loop (gen-label))
  1070.       (do-regs (gen-label))
  1071.       (done (gen-label)))
  1072.       (when (< fixed register-arg-count)
  1073.     ;; Save a pointer to the results so we can fill in register args.
  1074.     ;; We don't need this if there are more fixed args than reg args.
  1075.     (move result csp-tn))
  1076.       ;; Allocate the space on the stack.
  1077.       (cond ((zerop fixed)
  1078.          (inst beq nargs-tn done)
  1079.          (inst addu csp-tn csp-tn nargs-tn))
  1080.         (t
  1081.          (inst addu count nargs-tn (fixnum (- fixed)))
  1082.          (inst blez count done)
  1083.          (inst nop)
  1084.          (inst addu csp-tn csp-tn count)))
  1085.       (when (< fixed register-arg-count)
  1086.     ;; We must stop when we run out of stack args, not when we run out of
  1087.     ;; more args.
  1088.     (inst addu count nargs-tn (fixnum (- register-arg-count))))
  1089.       ;; Everything of interest in registers.
  1090.       (inst blez count do-regs)
  1091.       ;; Initialize dst to be end of stack.
  1092.       (move dst csp-tn)
  1093.       ;; Initialize src to be end of args.
  1094.       (inst addu src fp-tn nargs-tn)
  1095.  
  1096.       (emit-label loop)
  1097.       ;; *--dst = *--src, --count
  1098.       (inst addu src src (- vm:word-bytes))
  1099.       (inst addu count count (fixnum -1))
  1100.       (loadw temp src)
  1101.       (inst addu dst dst (- vm:word-bytes))
  1102.       (inst bgtz count loop)
  1103.       (storew temp dst)
  1104.  
  1105.       (emit-label do-regs)
  1106.       (when (< fixed register-arg-count)
  1107.     ;; Now we have to deposit any more args that showed up in registers.
  1108.     ;; We know there is at least one more arg, otherwise we would have
  1109.     ;; branched to done up at the top.
  1110.     (inst subu count nargs-tn (fixnum (1+ fixed)))
  1111.     (do ((i fixed (1+ i)))
  1112.         ((>= i register-arg-count))
  1113.       ;; Is this the last one?
  1114.       (inst beq count done)
  1115.       ;; Store it relative to the pointer saved at the start.
  1116.       (storew (nth i register-arg-tns) result (- i fixed))
  1117.       ;; Decrement count.
  1118.       (inst subu count (fixnum 1))))
  1119.       (emit-label done))))
  1120.  
  1121.  
  1122. ;;; More args are stored consequtively on the stack, starting immediately at
  1123. ;;; the context pointer.  The context pointer is not typed, so the lowtag is 0.
  1124. ;;;
  1125. (define-vop (more-arg word-index-ref)
  1126.   (:variant 0 0)
  1127.   (:translate %more-arg))
  1128.  
  1129.  
  1130. ;;; Turn more arg (context, count) into a list.
  1131. ;;;
  1132. (define-vop (listify-rest-args)
  1133.   (:args (context-arg :target context :scs (descriptor-reg))
  1134.      (count-arg :target count :scs (any-reg)))
  1135.   (:arg-types * tagged-num)
  1136.   (:temporary (:scs (any-reg) :from (:argument 0)) context)
  1137.   (:temporary (:scs (any-reg) :from (:argument 1)) count)
  1138.   (:temporary (:scs (descriptor-reg) :from :eval) temp)
  1139.   (:temporary (:scs (non-descriptor-reg) :from :eval) ndescr dst)
  1140.   (:results (result :scs (descriptor-reg)))
  1141.   (:translate %listify-rest-args)
  1142.   (:policy :safe)
  1143.   (:generator 20
  1144.     (let ((enter (gen-label))
  1145.       (loop (gen-label))
  1146.       (done (gen-label)))
  1147.       (move context context-arg)
  1148.       (move count count-arg)
  1149.       ;; Check to see if there are any arguments.
  1150.       (inst beq count zero-tn done)
  1151.       (move result null-tn)
  1152.  
  1153.       ;; We need to do this atomically.
  1154.       (pseudo-atomic (ndescr)
  1155.     ;; Allocate a cons (2 words) for each item.
  1156.     (inst addu result alloc-tn vm:list-pointer-type)
  1157.     (move dst result)
  1158.     (inst addu alloc-tn alloc-tn count)
  1159.     (inst b enter)
  1160.     (inst addu alloc-tn alloc-tn count)
  1161.  
  1162.     ;; Store the current cons in the cdr of the previous cons.
  1163.     (emit-label loop)
  1164.     (storew dst dst -1 vm:list-pointer-type)
  1165.  
  1166.     ;; Grab one value and stash it in the car of this cons.
  1167.     (emit-label enter)
  1168.     (loadw temp context)
  1169.     (inst addu context context vm:word-bytes)
  1170.     (storew temp dst 0 vm:list-pointer-type)
  1171.  
  1172.     ;; Dec count, and if != zero, go back for more.
  1173.     (inst addu count count (fixnum -1))
  1174.     (inst bne count zero-tn loop)
  1175.     (inst addu dst dst (* 2 vm:word-bytes))
  1176.  
  1177.     ;; NIL out the last cons.
  1178.     (storew null-tn dst -1 vm:list-pointer-type))
  1179.       (emit-label done))))
  1180.  
  1181.  
  1182.  
  1183. ;;; Return the location and size of the more arg glob created by Copy-More-Arg.
  1184. ;;; Supplied is the total number of arguments supplied (originally passed in
  1185. ;;; NARGS.)  Fixed is the number of non-rest arguments.
  1186. ;;;
  1187. ;;; We must duplicate some of the work done by Copy-More-Arg, since at that
  1188. ;;; time the environment is in a pretty brain-damaged state, preventing this
  1189. ;;; info from being returned as values.  What we do is compute
  1190. ;;; supplied - fixed, and return a pointer that many words below the current
  1191. ;;; stack top.
  1192. ;;;
  1193. (define-vop (more-arg-context)
  1194.   (:args (supplied :scs (any-reg)))
  1195.   (:arg-types positive-fixnum)
  1196.   (:info fixed)
  1197.   (:results
  1198.    (context :scs (descriptor-reg))
  1199.    (count :scs (any-reg)))
  1200.   (:generator 5
  1201.     (inst addu count supplied (fixnum (- fixed)))
  1202.     (inst subu context csp-tn count)))
  1203.  
  1204.  
  1205. ;;; Signal wrong argument count error if Nargs isn't = to Count.
  1206. ;;;
  1207. (define-vop (verify-argument-count)
  1208.   (:args (nargs :scs (any-reg)))
  1209.   (:arg-types positive-fixnum)
  1210.   (:temporary (:scs (any-reg) :type fixnum) temp)
  1211.   (:info count)
  1212.   (:vop-var vop)
  1213.   (:save-p :compute-only)
  1214.   (:generator 3
  1215.     (let ((err-lab
  1216.        (generate-error-code vop invalid-argument-count-error nargs)))
  1217.       (cond ((zerop count)
  1218.          (inst bne nargs zero-tn err-lab)
  1219.          (inst nop))
  1220.         (t
  1221.          (inst li temp (fixnum count))
  1222.          (inst bne nargs temp err-lab)
  1223.          (inst nop))))))
  1224.  
  1225. ;;; Signal an argument count error.
  1226. ;;;
  1227. (macrolet ((frob (name error &rest args)
  1228.          `(define-vop (,name)
  1229.         (:args ,@(mapcar #'(lambda (arg)
  1230.                      `(,arg :scs (any-reg descriptor-reg)))
  1231.                  args))
  1232.         (:vop-var vop)
  1233.         (:save-p :compute-only)
  1234.         (:generator 1000
  1235.           (error-call vop ,error ,@args)))))
  1236.   (frob argument-count-error invalid-argument-count-error nargs)
  1237.   (frob type-check-error object-not-type-error object type)
  1238.   (frob odd-keyword-arguments-error odd-keyword-arguments-error)
  1239.   (frob unknown-keyword-argument-error unknown-keyword-argument-error key)
  1240.   (frob nil-function-returned-error nil-function-returned-error fun))
  1241.